package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.product.service.TestService;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class TestServiceImpl implements TestService {

    /*
    1.  先在缓存存储一个num = 0；
    2.  在这个程序中获取这个num
            true:   num+1; 并写回缓存.
            false:  return;
     */

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;


    @Override
    public void testLock() {
        //  获取到锁对象
        RLock lock = redissonClient.getLock("lock");
        //  上锁
        lock.lock();
        //  业务逻辑
        try {
            //  从缓存中获取数据
            String num = redisTemplate.opsForValue().get("num");
            //  null return;
            if (StringUtils.isEmpty(num)){
                return;
            }
            //  数据类型转换
            int numValue = Integer.parseInt(num);
            //  异常：
            //  int i = 1/0;
            //  写回缓存
            this.redisTemplate.opsForValue().set("num",String.valueOf(++numValue));
        } catch (NumberFormatException e) {
            throw new RuntimeException(e);
        } finally {
            //  解锁：
            lock.unlock();
        }
    }

    @Override
    public String readLock() {
        //  获取锁对象
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("anyRWLock");
        RLock rLock = rwlock.readLock();
        //  上锁.
        rLock.lock(10,TimeUnit.SECONDS);
        //  读业务逻辑
        String msg = this.redisTemplate.opsForValue().get("msg");
        //  解锁： 想测试读写锁具有互斥性！
        //  rLock.unlock();
        //  返回数据
        return msg;
    }

    @Override
    public String writeLock() {
        //  获取锁对象
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("anyRWLock");
        RLock rLock = rwlock.writeLock();
        //  上锁.
        rLock.lock(10,TimeUnit.SECONDS);
        //  写业务逻辑
        this.redisTemplate.opsForValue().set("msg",UUID.randomUUID().toString());
        //  解锁： 想测试读写锁具有互斥性！
        //  rLock.unlock();
        //  返回数据
        return "写入完成...";
    }

/*        @Override
        public void testLock() {
            //  上锁
            //  setnx key value;
            //  Boolean result = this.redisTemplate.opsForValue().setIfAbsent("lock", "ok");
            //  set lock ok ex 10 nx
            //  将固定值，变为动态值！
            String uuid = UUID.randomUUID().toString();
            Boolean result = this.redisTemplate.opsForValue().setIfAbsent("lock", uuid,3, TimeUnit.SECONDS);
            //  获取到锁
            if (result){
                //  从缓存中获取数据
                String num = redisTemplate.opsForValue().get("num");
                //  null return;
                if (StringUtils.isEmpty(num)){
                    return;
                }
                //  数据类型转换
                int numValue = Integer.parseInt(num);
                //  异常：
                //  int i = 1/0;
                //  写回缓存
                this.redisTemplate.opsForValue().set("num",String.valueOf(++numValue));
                //  释放锁;
                String scriptText = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                        "then\n" +
                        "    return redis.call(\"del\",KEYS[1])\n" +
                        "else\n" +
                        "    return 0\n" +
                        "end";
                //  设置lua脚本;
                DefaultRedisScript redisScript = new DefaultRedisScript<>();
                redisScript.setScriptText(scriptText);
                redisScript.setResultType(Long.class);
                //  lua脚本 key value;
                this.redisTemplate.execute(redisScript, Arrays.asList("lock"),uuid);

                //            while (uuid.equals(this.redisTemplate.opsForValue().get("lock"))){
                //                //  删除锁.
                //                this.redisTemplate.delete("lock");
                //            }

            } else {
                try {
                    Thread.sleep(100);
                    testLock();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

        }*/
}
